//使用互斥锁的方式解决cp问题：生产者和消费者共用同一把锁，可以达到互斥同步-----也就是使用阻塞队列

//生产者消费者用一把锁，难道不会导致由于互斥锁让整个生产消费的模型是低效的吗？当然不是，我们要把格局打开，生产者也要花时间获取数据，消费者也要花之间处理数据
//所以，所有的生产者会并发的开始获取数据，获取数据完成的生产者才会去竞争锁，去生产资源到仓库中
//所有的消费者获取仓库中的数据后，会开始处理数据，处理完成的消费者才会从新来竞争锁
//所以：单看多个生产者消费者竞争同一把锁，是低效的，但是这使得可以有多个生产者可以并发的获取数据，多个消费者可以并发的处理数据，这样这个总体来看，整个生产者消费者模型就是十分高效的

//使用阻塞队列完成cp问题只能有一把锁的原因：确保在任何时候只有一个线程可以修改队列。生产者在向队列中添加元素时会获取这个锁，消费者在从队列中取出元素时也会获取这个锁。这种做法确保了队列的状态在修改时不会被并发访问破坏。
//并且，多个线程同时访问该队列的时候，由于STL中几乎所有的操作都是不可重入的，会导致队列数据错乱访问等问题。

//注意：锁资源不但在消费者或者生产者内部抢，生产者和消费者之间也会抢，所以锁资源会一定程度上让整个模型效率下降，但是这是为了保持数据的同步和互斥，保证了多个执行流对一份资源的正确无误的使用，这是必要的也是不可避免的

#include"BlockQueue.hpp"
#include"task.hpp"
#include<unistd.h>
#include<ctime>
//消费者：
void *Consumer(void *args)
{
    BlockQueue<Task>*bq=static_cast<BlockQueue<Task>*>(args);
    while(true)
    {
        //消费：
        Task t =bq->pop();
        //处理数据：
        //线程在处理数据的时候是不占用锁的，模拟了对数据的处理，所以对数据的处理是并发的，所以整体看该模型是高效的
        t();
        cout<<"处理任务："<<t.GetTask()<<"运算结果是："<<t.GetResult()<<"thread id:"<<pthread_self()<<endl;
    }
    return nullptr;
}
//生产者：
void *Productor(void *args)
{
    int len=opers.size();
    BlockQueue<Task>*bq=static_cast<BlockQueue<Task>*>(args);
    while(true)
    {
        //模拟生产者产生数据：
        int data1=rand()%10+1;
        usleep(10);
        int data2=rand()%10;
        char op=opers[rand()%len];
        Task t(data1,data2,op);
        //产生数据的过程也是并发的，不受锁的约束

        //生产：
        bq->push(t);
        cout<<"生产了一个任务："<<t.GetTask()<<"thread id:"<<pthread_self()<<endl;
        //让生产者慢一点：
        sleep(1);
    }
    return nullptr;
}
int main()
{
    srand(time(nullptr));
    BlockQueue<Task>*bq=new BlockQueue<Task>();
    pthread_t c[3];
    pthread_t p[5];
    //创建多个消费者，生产者线程：
    for(int i=0;i<3;i++)
    {
        pthread_create(c+i,nullptr,Consumer,bq);//c是数组首地址，也就是只想数组首地址的指针，c+i很巧妙地把对应变量的地址进行了传参
    }
    for(int i=0;i<5;i++)
    {
        pthread_create(p+i,nullptr,Productor,bq);
    }
    //对所有线程释放：（阻塞等待的方式）
    for(int i=0;i<3;i++)
    {
        pthread_join(c[i],nullptr);
    }
    for(int i=0;i<5;i++)
    {
        pthread_join(p[i],nullptr);
    }
    delete bq;
    return 0;
}


